package com.catazy.album.presentation.screen.albumlist

import androidx.compose.runtime.Immutable
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.catazy.album.domain.model.Album
import com.catazy.album.domain.usecase.GetAlbumListUseCase
import com.catazy.album.presentation.screen.albumlist.AlbumListViewModel.Action
import com.catazy.album.presentation.screen.albumlist.AlbumListViewModel.UiState
import com.catazy.album.presentation.screen.albumlist.AlbumListViewModel.UiState.Content
import com.catazy.album.presentation.screen.albumlist.AlbumListViewModel.UiState.Error
import com.catazy.album.presentation.screen.albumlist.AlbumListViewModel.UiState.Loading
import com.catazy.base.domain.result.Result
import com.catazy.base.presentation.nav.NavManager
import com.catazy.base.presentation.viewmodel.BaseAction
import com.catazy.base.presentation.viewmodel.BaseState
import com.catazy.base.presentation.viewmodel.BaseViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

/**
 * - 作者: Tao
 * - 日期: 2024/12/25
 * - 时间: 09:25
 * - 描述: AlbumListViewModel 是负责处理专辑列表相关操作的 ViewModel。
 *
 * @param savedStateHandle 用于保存和恢复状态的辅助类。
 * @param navManager 用于导航的辅助类。
 * @param getAlbumListUseCase 用于获取专辑列表的 UseCase。
 */
internal class AlbumListViewModel(
    private val savedStateHandle: SavedStateHandle,
    private val navManager: NavManager,
    private val getAlbumListUseCase: GetAlbumListUseCase
) : BaseViewModel<UiState, Action>(Loading) {

    companion object {
        // 默认的查询名称，当没有保存的查询状态时使用。
        const val DEFAULT_QUERY_NAME = "Jackson"
        // 用于保存查询关键字的键。
        private const val SAVED_QUERY_KEY = "query"
    }

    /**
     * 当进入专辑列表时调用此方法。
     * 它会从保存的状态中获取查询关键字，如果没有则使用默认值，并加载专辑列表。
     *
     * @param query 可选的查询关键字，如果未提供，则从保存的状态或使用默认值获取。
     */
    fun onEnter(
        query: String? = (savedStateHandle.get(SAVED_QUERY_KEY) as? String) ?: DEFAULT_QUERY_NAME
    ) {
        getAlbumList(query)
    }

    // 用于取消先前的异步任务，以避免重复请求。
    private var job: Job? = null

    /**
     * 加载专辑列表的方法。
     * 如果有正在进行的请求，则取消它以避免请求的重复执行。
     *
     * @param query 查询关键字，用于搜索特定的专辑列表。
     */
    private fun getAlbumList(query: String?) {
        if (job != null) {
            job?.cancel()
            job = null
        }

        // 保存当前的查询关键字，以便于配置变化后可以恢复。
        savedStateHandle[SAVED_QUERY_KEY] = query

        // 在 ViewModel 的作用域内启动一个新的协程来执行数据请求。
        job = viewModelScope.launch {
            getAlbumListUseCase(query).also { result ->
                // 根据请求结果发送不同的动作。
                val action = when (result) {
                    is Result.Success -> {
                        if (result.data.isEmpty()) {
                            Action.AlbumListLoadFailure
                        } else {
                            Action.AlbumListLoadSuccess(result.data)
                        }
                    }

                    is Result.Failure -> Action.AlbumListLoadFailure
                }

                sendAction(action)
            }
        }
    }

    /**
     * 当点击专辑时调用此方法进行导航。
     *
     * @param album 被点击的专辑，包含导航所需的信息。
     */
    fun onAlbumClick(album: Album) {
        // 创建导航指令，从专辑列表导航到专辑详情页面。
        val navDirections = AlbumListFragmentDirections.actionAlbumListToAlbumDetail(
            album.artist,
            album.name,
            album.mbId
        )
        navManager.navigate(navDirections)
    }

    /**
     * Action 接口的实现，用于表示专辑列表加载的成功或失败。
     */
    internal sealed interface Action : BaseAction<UiState> {
        /**
         * 专辑列表加载成功的状态。
         * @param albums 加载成功的专辑列表。
         */
        data class AlbumListLoadSuccess(private val albums: List<Album>) : Action {
            override fun reduce(state: UiState) = Content(albums)
        }

        /**
         * 专辑列表加载失败的状态。
         */
        data object AlbumListLoadFailure : Action {
            override fun reduce(state: UiState) = Error
        }
    }

    /**
     * UiState 接口的实现，表示 UI 的不同状态。
     */
    @Immutable
    internal sealed interface UiState : BaseState {
        /**
         * 内容加载成功的状态。
         * @param albums 加载成功的专辑列表。
         */
        data class Content(val albums: List<Album>) : UiState
        /**
         * 加载中的状态。
         */
        data object Loading : UiState
        /**
         * 错误状态。
         */
        data object Error : UiState
    }
}